#include <stdio.h>
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <fcntl.h>
#include <fstream>
#include <vector>
#include <filesystem>
#include <chrono>
#include "Util/logc.h"
#include "ConfigApi.h"
#include "Net.h"
#include "ini.h"
#include "TailDevice.h"

using  namespace  HidDeviceNameSpace;


const std::string DevHardwarePath = "/mnt/mtd/Sys/hardwareTest.ini";

const char* LAN_AP = "wlan1";

const int MIN_IP = 50;
const int MAX_IP = 150;


enum{
    DEFAULT_DEV,
    AIR_DEV,
    ROOMS_DEV
};




bool TailDevice::SendMatchTailMessage(){
    //拼接Tail配对锁需要的信息    
    Json::Value table;
    SpliceTailMatchMessage(table);
    //下发配对信息到Tail
    SendMesage(table);
    return true;
}


bool TailDevice::SendMesage(Json::Value table){
    awi_dfu_t *dfu = awi_dfu_new();

    int fd = open(m_device_file_path.c_str(), O_RDWR, 0666);
    if(fd <= 0){
        errorf("open device fail %s\n", m_device_file_path.c_str());
        return false;
    }

    awi_dfu_set_send_notify(dfu, (void *)fd, [](void *notify_ths, const uint8_t *data, int bytes){
            int fd = (int)notify_ths;
            int8_t buffer[1024];
            int me_size = 256;
            buffer[0] = 5;
            memset(buffer + 1, 0, me_size - 1);
            memcpy(buffer + 1, data, bytes);
            write(fd, buffer, me_size);
            // printf("!!!!!!!!! send hid message fd %d, data bytes %d, write ret %d\n", fd, bytes, ret);
    });

    awi_dfu_set_recv_notify(dfu, this, [](void *notify_ths, uint16_t ctrl, 
            uint16_t dst, uint16_t src, uint16_t version, 
            const uint8_t *payload, int bytes){
                warnf("recvice tail rep save mac address to config\n");
                TailDevice *own = (TailDevice *)notify_ths;
                own->deviceInfoRecv(ctrl, dst, src, version, payload, bytes);
    });

    unsigned char buffer[1024] = {0};
	Json::FastWriter writer;
	std::string strJson1 = writer.write(table);	
	memcpy(buffer, strJson1.c_str(), strlen(strJson1.c_str()));
    
    awi_dfu_send(dfu, HID_CMD_ROOMS_TAIL_MATCH_REQ, 0xFFFF, 0x01, buffer, strlen(strJson1.c_str())); //reset
    

    auto read_process = [](int fd, awi_dfu_t * dfu){
        fd_set rfds;
        FD_ZERO(&rfds);
		FD_SET(fd, &rfds);
        char buffer[256];

        struct timeval tv;
        tv.tv_sec = 1; 
        tv.tv_usec = 0;

        int max_fail_count = 5;
        while (true) {
            int ret = select(fd + 1, &rfds, NULL, NULL, &tv);
            if(ret <= 0){
                max_fail_count--;
                continue;
            }
            if (FD_ISSET(fd, &rfds)){
                int len = read(fd, buffer, 256);
                // aw_print("len = %d", len);
                if (len <= 0) {
                    printf("read   failed \n");
                    break;
                }
                // printf("recv[");
                // for (int i = 0; i < len; ++i) {
                //     printf("%x ", (uint8_t)buffer[i]);
                // }
                // printf("]\r\n");
                awi_dfu_recv(dfu, buffer+1, len+1);
                break;
            }
        }
    };
    auto deviceinfo_task = std::async(std::launch::async, read_process, fd, dfu);
    deviceinfo_task.wait();
    
    close(fd);
    awi_dfu_del(dfu);
    return true;
}




void TailDevice::deviceInfoRecv(uint16_t ctrl, uint16_t dst, uint16_t src, uint16_t version, 
            const uint8_t *payload, int bytes){
    
    aw_print("ctrl = %x dst = %x src = %x version = %d bytes = %d", ctrl, dst, src, version, bytes);
	printf("recved payload [");
	for (int i = 0; i < bytes; ++i) {
		printf("%x ", payload[i]);
	}
	printf("]\r\n");

	switch (ctrl) {
        case 0x0081:
        {
            uint32_t *pv = (uint32_t*)payload;
            uint32_t rlt = awi_ntohl(pv[0]);
            if (rlt == 0) {
                aw_print("reset success");
            }
            else if (rlt == 1) {
                aw_print("reset fail and dev will reboot");
            }
            else {
                aw_print("unexpect rlt = %d", rlt);
            }
            break;
        }
        case 0x0082:
        {
            uint16_t *pv = (uint16_t*)payload;
            uint16_t dev_count = awi_htons(pv[0]);
            aw_print("dev count = %d", dev_count);

            int pos = 2;
            for (int i = 0; i < dev_count; ++i) {
                uint16_t dev_type;
                char product_name[64];
                char phy_version[64];
                char soft_version[64];
                char serial_number[64];
                char unique_id[64];

                product_name[0] = '\0';
                phy_version[0] = '\0';
                soft_version[0] = '\0';
                serial_number[0] = '\0';
                unique_id[0] = '\0';
                
                uint16_t *ptype = (uint16_t*)(payload + pos);
                pos += 2;
                dev_type = awi_ntohs(ptype[0]);
                uint32_t *pflag = (uint32_t*)(payload + pos);
                uint32_t flag = awi_ntohl(pflag[0]);
                pos += 4;
                
    #define PRODUCT_NAME_SHIFT 0
    #define PHY_VERSION_SHIFT 1
    #define SOFT_VERSION_SHIFT 2
    #define SERIAL_NUMBER_SHIFT 3
    #define UNIQUE_ID_SHIFT 4

                for (int j = 0; j < 32; ++j) {
                    if ((flag & (1 << j)) == 0) {
                        continue;
                    }
                    aw_print("catch shift %d", j);
                    switch (j) {
                    case PRODUCT_NAME_SHIFT: 
                    {
                        uint8_t len = payload[pos++];
                        memcpy(product_name, payload + pos, len);
                        product_name[len] = '\0';
                        pos += len;
                        break;
                    }
                    case PHY_VERSION_SHIFT:
                    {
                        uint8_t len = payload[pos++];
                        memcpy(phy_version, payload + pos, len);
                        phy_version[len] = '\0';
                        pos += len;
                        break;
                    }
                    case SOFT_VERSION_SHIFT:
                    {
                        uint8_t len = payload[pos++];
                        memcpy(soft_version, payload + pos, len);
                        soft_version[len] = '\0';
                        pos += len;
                        break;
                    }
                    case SERIAL_NUMBER_SHIFT:
                    {
                        uint8_t len = payload[pos++];
                        memcpy(serial_number, payload + pos, len);
                        serial_number[len] = '\0';
                        pos += len;
                        break;
                    }
                    case UNIQUE_ID_SHIFT:
                    {
                        uint8_t len = payload[pos++];
                        memcpy(unique_id, payload + pos, len);
                        unique_id[len] = '\0';
                        pos += len;
                        break;
                    }
                    default: {
                        uint8_t len = payload[pos++];
                        pos += len;
                        break;
                    }
                    }
                }
                aw_print("%d : dev type = [%x] product name = [%s] phy version = [%s] soft version = [%s] serial number = [%s] unique id = [%s]",
                            i, dev_type, product_name, phy_version, soft_version, serial_number, unique_id);
                m_product_name = product_name;
                m_phy_version = phy_version;
                m_soft_version = soft_version;
                m_serial_number = serial_number;
                m_unique_id = unique_id;
            }
            break;
        }
        case HID_CMD_ROOMS_TAIL_MATCH_REP:
        {
            int i;
            char macaddrStr[32] = {0};
            Json::Value TailTable;
          

            sprintf(macaddrStr, "%02x:%02x:%02x:%02x:%02x:%02x",
                payload[0], payload[1], payload[2], payload[3], payload[4], payload[5]);

            TailTable["mac"] = macaddrStr;
            bool ret = ConfigApi::IConfigInterface::GetInstance()->Set("Tail", TailTable, ConfigApi::ConfigOptions::ConfigOptionPart);
            break;
        }
	}
}



bool TailDevice::SpliceTailMatchMessage(Json::Value &table){
    //获取AP的ssid和keys
    Json::Value apTable;
    ConfigApi::IConfigInterface::GetInstance()->Get("APInfo", apTable);
    if(!apTable.isMember("Password") || !apTable.isMember("Ssid")){
        errorf("error get apinfo json\n");
        return -1;
    }
    table["k"] = apTable["Password"].asString();

    char snid[64] = {0};
    int status_get_snid = INI_KeyGetString(DevHardwarePath.c_str(), "hardwareTest", "snid", snid);
    if(status_get_snid < 0){
        errorf("openService get snid fail\n");
    }
    
    std::string sn = snid;		
    table["s"] = apTable["Ssid"].asString();
    //获取Bssid
    char macaddr[32] = {0};
    if(NetGetMAC("wlan1", macaddr, 32)){
        errorf("Faild to get wlan1 macaddr\n");
        return -1;
    }
    table["b"] = macaddr;
    //获取信道下发
    int channel = -1;
    for(int i = 10; i < 100; i++){
        if(getApChannel("/var/rtl_hostapd.conf", channel)){
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    if(channel == -1){
        errorf("Cannot get ap channel\n");
    }else{
        table["c"] = channel;
    }

    
    
    Json::Value devTable;
    ConfigApi::IConfigInterface::GetInstance()->Get("DeviceInfo", devTable);
    if(devTable.isMember("device_type")){
        std::string devType = devTable["device_type"].asString();
        if(devType == "ROOMS"){
            table["t"] = ROOMS_DEV;
        }else if(devType == "AIR"){
            table["t"] = AIR_DEV;
        }
    }

    char ipaddrStr[16] = {0};
    char netmaskStr[16] = {0};    
    if(NetGetHostIPEx(LAN_AP, ipaddrStr, sizeof(ipaddrStr), netmaskStr, sizeof(netmaskStr)) == 0)
    {
        Json::Value tailTable;
        ConfigApi::IConfigInterface::GetInstance()->Get("Tail", tailTable);

        if(tailTable.isMember("Index"))
        {
    	    int index = tailTable["Index"].asInt();
            if(index >= MAX_IP || index < MIN_IP)
            {
                index = MIN_IP;   
            }
            else
            {
                index++;
            }

            tailTable["Index"] = index;
            ConfigApi::IConfigInterface::GetInstance()->Set("Tail", tailTable, ConfigApi::ConfigOptions::ConfigOptionPart);

            std::string assignIp = ipaddrStr;
            std::string lastParam =  std::to_string(index);
            size_t lastDotIndex = assignIp.rfind('.');
            if (lastDotIndex != std::string::npos)
            {
                assignIp.replace(lastDotIndex + 1, assignIp.size() - lastDotIndex - 1, lastParam);                
                table["ip"] = assignIp;
            }
    	}
    }


    warnf("matchTail end,params=%s\n", table.toStyledString().c_str());
    return true;
}

bool TailDevice::getApChannel(std::string filename, int &channel){
    // 尝试打开文件
    std::ifstream inputFile(filename);
    
    if (!inputFile.is_open()) {
        std::cerr << "无法打开文件: " << filename << std::endl;
        return false;
    }

    std::string line;
    while (std::getline(inputFile, line)) {
        // 在控制台中打印每一行
        std::cout << line << std::endl;
        size_t pos = line.find("channel=");
        size_t len = strlen("channel=");
        if(pos != std::string::npos){
            std::string channels = line.substr(pos + len, line.size() - len);
            channel = std::stoi(channels);
            break;
        }
    }

    inputFile.close(); // 关闭文件

    return true;
}




TailDevice::TailDevice(const std::string& device_path, std::string& product_model, const std::string& product_name, const std::string& phy_version, 
        const std::string& soft_version, const std::string& serial_number, 
        const std::string& unique_id, std::vector<HidDevInfo> sub_devices):HidDevice(device_path, product_model, product_name, phy_version, 
        soft_version, serial_number, unique_id, sub_devices){
    
    //Write this device type for now todo::
    m_upgrade = std::make_shared<DeviceUpgradeUtil>(A15SERIES);
    SendMatchTailMessage();
}

TailDevice::~TailDevice(){
    
}



bool TailDevice::Upgrade(const std::string& file_path){
    std::lock_guard<std::recursive_mutex> guard(m_mux);
    return m_upgrade->Upgrade(m_device_file_path, file_path);
}

